perm filename PAGE10.WEB[MF,ALS] blob sn#778362 filedate 1984-12-04 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00002 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00002 00002	@* Optional modes of output.
C00018 ENDMK
C⊗;
@* Optional modes of output.
\.{DVIIMAGEN} will print different quantities of information based on some
options that the user must specify: The |out_mode| level is set to one of
four values (|errors_only|, |terse|, |verbose|, |the_works|), giving
different degrees of output; and the typeout can be confined to a
restricted subset of the pages by specifying the desired starting page and
the maximum number of pages. Furthermore there is an option to specify the
resolution of an assumed discrete output device, so that pixel-oriented
calculations will be shown; and there is an option to override the
magnification factor that is stated in the \.{DVI} file.

The starting page is specified by giving a sequence of 1 to 10 numbers or
asterisks separated by dots. For example, the specification `\.{1.*.-5}'
can be used to refer to a page output by \TeX\ when $\.{\\count0}=1$
and $\.{\\count2}=-5$. (Recall that |bop| commands in a \.{DVI} file
are followed by ten `count' values.) An asterisk matches any number,
so the `\.*' in `\.{1.*.-5}' means that \.{\\count1} is ignored when
specifying the first page. If several pages match the given specification,
\.{DVIIMAGEN} will begin with the earliest such page in the file. The
default specification `\.*' (which matches all pages) therefore denotes
the page at the beginning of the file.

When \.{DVIIMAGEN} begins, it engages the user in a brief dialog so that the
options will be specified. This part of \.{DVIIMAGEN} requires nonstandard
\PASCAL\ constructions to handle the online interaction; so it may be
preferable in some cases to omit the dialog and simply to stick to the
default options (|out_mode=the_works|, starting page `\.*',
|max_pages=1000000|, |resolution=300.0|, |new_mag=0|).  On other hand, the
system-dependent routines that are needed are not complicated, so it will
not be terribly difficult to introduce them.
@↑system dependencies@>

@d errors_only=0 {value of |out_mode| when minimal printing occurs}
@d terse=1 {value of |out_mode| for abbreviated output}
@d verbose=2 {value of |out_mode| for detailed tracing}
@d the_works=3 {|verbose|, plus check of postamble if |random_reading|}

@<Glob...@>=
@!out_mode:errors_only..the_works; {controls the amount of output}
@!max_pages:integer; {at most this many |bop..eop| pages will be printed}
@!resolution:real; {pixels per inch}
@!new_mag:integer; {if positive, overrides the postamble's magnification}

@ The starting page specification is recorded in two global arrays called
|start_count| and |start_there|. For example, `\.{1.*.-5}' is represented
by |start_there[0]=true|, |start_count[0]=1|, |start_there[1]=false|,
|start_there[2]=true|, |start_count[2]=-5|.
We also set |start_vals=2|, to indicate that count 2 was the last one
mentioned. The other values of |start_count| and |start_there| are not
important, in this example.

@<Glob...@>=
@!start_count:array[0..9] of integer; {count values to select starting page}
@!start_there:array[0..9] of boolean; {is the |start_count| value relevant?}
@!start_vals:0..9; {the last count considered significant}
@!count:array[0..9] of integer; {the count values on the current page}

@ @<Set init...@>=
out_mode←the_works; max_pages←1000000; start_vals←0; start_there[0]←false;

@ Here is a simple subroutine that tests if the current page might be the
starting page.

@p function start_match:boolean; {does |count| match the starting spec?}
var k:0..9;	{loop index}
@!match:boolean; {does everything match so far?}
begin match←true;
for k←0 to start_vals do
	if start_there[k]∧(start_count[k]≠count[k]) then match←false;
start_match←match;
end;

@ The |input_ln| routine waits for the user to type a line at his or her
terminal; then it puts ASCII-code equivalents for the characters on that line
into the |buffer| array. The |term_in| file is used for terminal input,
and |term_out| for terminal output.
@↑system dependencies@>

@<Glob...@>=
@!buffer:array[0..terminal_line_length] of ASCII_code;
@!term_in:text_file; {the terminal, considered as an input file}
@!term_out:text_file; {the terminal, considered as an output file}

@ Since the terminal is being used for both input and output, some systems
need a special routine to make sure that the user can see a prompt message
before waiting for input based on that message. (Otherwise the message
may just be sitting in a hidden buffer somewhere, and the user will have
no idea what the program is waiting for.) We shall invoke a system-dependent
subroutine |update_terminal| in order to avoid this problem.
@↑system dependencies@>

@d update_terminal == break(term_out) {empty the terminal output buffer}

@ During the dialog, \.{DVIIMAGEN} will treat the first blank space in a
line as the end of that line. Therefore |input_ln| makes sure that there
is always at least one blank space in |buffer|.
@↑system dependencies@>

@p procedure input_ln; {inputs a line from the terminal}
var k:0..terminal_line_length;
begin update_terminal; reset(term_in);
if eoln(term_in) then read_ln(term_in);
k←0;
while (k<terminal_line_length)∧ not eoln(term_in) do
	begin buffer[k]←xord[term_in↑]; incr(k); get(term_in);
	end;
buffer[k]←" ";
end;

@ The global variable |buf_ptr| is used while scanning each line of input;
it points to the first unread character in |buffer|.

@<Glob...@>=
@!buf_ptr:0..terminal_line_length; {the number of characters read}

@ Here is a routine that scans a (possibly signed) integer and computes
the decimal value. If no decimal integer starts at |buf_ptr|, the
value 0 is returned. The integer should be less than $2↑{31}$ in
absolute value.

@p function get_integer:integer;
var x:integer; {accumulates the value}
@!negative:boolean; {should the value be negated?}
begin if buffer[buf_ptr]="-" then
	begin negative←true; incr(buf_ptr);
	end
else negative←false;
x←0;
while (buffer[buf_ptr]≥"0")∧(buffer[buf_ptr]≤"9") do
	begin x←10*x+buffer[buf_ptr]-"0"; incr(buf_ptr);
	end;
if negative then get_integer←-x @+ else get_integer←x;
end;

@ The selected options are put into global variables by the |dialog|
procedure, which is called just as \.{DVIIMAGEN} begins.
@↑system dependencies@>

@p procedure dialog;
label 1,2,3,4,5;
var k:integer; {loop variable}
begin rewrite(term_out); {prepare the terminal for output}
write_ln(term_out,banner);
@<Determine the desired |out_mode|@>;
@<Determine the desired |start_count| values@>;
@<Determine the desired |max_pages|@>;
@<Determine the desired |resolution|@>;
@<Determine the desired |new_mag|@>;
@<Print all the selected options@>;
end;

@ @<Determine the desired |out_mode|@>=
1: write(term_out,'Output level (default=3, ? for help): ');
out_mode←the_works; input_ln;
if buffer[0]≠" " then
	if (buffer[0]≥"0")∧(buffer[0]≤"3") then out_mode←buffer[0]-"0"
	else	begin write(term_out,'Type 3 for complete listing,');
		write(term_out,' 0 for errors only,');
		write_ln(term_out,' 1 or 2 for something in between.');
		goto 1;
		end

@ @<Determine the desired |start...@>=
2: write(term_out,'Starting page (default=*): ');
start_vals←0; start_there[0]←false;
input_ln; buf_ptr←0; k←0;
if buffer[0]≠" " then
	repeat if buffer[buf_ptr]="*" then
		begin start_there[k]←false; incr(buf_ptr);
		end
	else	begin start_there[k]←true; start_count[k]←get_integer;
		end;
	if (k<9)∧(buffer[buf_ptr]=".") then
		begin incr(k); incr(buf_ptr);
		end
	else if buffer[buf_ptr]=" " then start_vals←k
	else	begin write(term_out,'Type, e.g., 1.*.-5 to specify the ');
		write_ln(term_out,'first page with \count0=1, \count2=-5.');
		goto 2;
		end;
	until start_vals=k

@ @<Determine the desired |max_pages|@>=
3: write(term_out,'Maximum number of pages (default=1000000): ');
max_pages←1000000; input_ln; buf_ptr←0;
if buffer[0]≠" " then
	begin max_pages←get_integer;
	if max_pages≤0 then
		begin write_ln(term_out,'Please type a positive number.');
		goto 3;
		end;
	end

@ @<Determine the desired |resolution|@>=
4: write(term_out,'Assumed device resolution');
write(term_out,' in pixels per inch (default=240/1): ');
resolution←240.0; input_ln; buf_ptr←0;
if buffer[0]≠" " then
	begin k←get_integer;
	if (k>0)∧(buffer[buf_ptr]="/")∧
		(buffer[buf_ptr+1]>"0")∧(buffer[buf_ptr+1]≤"9") then
		begin incr(buf_ptr); resolution←k/get_integer;
		end
	else	begin write(term_out,'Type a ratio of positive integers;');
		write_ln(term_out,' (1 pixel per mm would be 254/10).');
		goto 4;
		end;
	end

@ @<Determine the desired |new_mag|@>=
5: write(term_out,'New magnification (default=0 to keep the old one): ');
new_mag←0; input_ln; buf_ptr←0;
if buffer[0]≠" " then
	if (buffer[0]≥"0")∧(buffer[0]≤"9") then new_mag←get_integer
	else	begin write(term_out,'Type a positive integer to override ');
		write_ln(term_out,'the magnification in the DVI file.');
		goto 5;
		end

@ After the dialog is over, we print the options so that the user
can see what \.{DVIIMAGEN} thought was specified.

@<Print all the selected options@>=
print_ln('Options selected:');
@.Options selected@>
print('  Starting page = ');
for k←0 to start_vals do
	begin if start_there[k] then print(start_count[k]:1)
	else print('*');
	if k<start_vals then print('.')
	else print_ln(' ');
	end;
print_ln('  Maximum number of pages = ',max_pages:1);
print('  Output level = ',out_mode:1);
case out_mode of
errors_only: print_ln(' (showing bops, fonts, and error messages only)');
terse: print_ln(' (terse)');
verbose: print_ln(' (verbose)');
the_works: if random_reading then print_ln(' (the works)')
	else	begin out_mode←verbose;
		print_ln(' (the works: same as level 2 in this DVIIMAGEN)');
		end;
end;@/
print_ln('  Resolution = ',resolution:12:8,' pixels per inch');
if new_mag>0 then print_ln('  New magnification factor = ',new_mag/1000:8:3)